﻿using System;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using System.Reflection;
using NHibernate.Hql.Ast;
using NHibernate.Linq;
using NHibernate.Linq.Functions;
using NHibernate.Linq.Visitors;

namespace NHDay_Linq.ProviderExtensions
{
	public class ExtendedEqualsGenerator : BaseHqlGeneratorForMethod
	{
		public ExtendedEqualsGenerator()
		{
			// the methods call are used only to get info about the signature, the actual parameter is just ignored
			SupportedMethods = new[] { 
				ReflectionHelper.GetMethodDefinition<Byte>(x => x.Equals((Byte)0)),
				ReflectionHelper.GetMethodDefinition<SByte>(x => x.Equals((SByte)0)),
				ReflectionHelper.GetMethodDefinition<Int16>(x => x.Equals((Int16)0)),
				ReflectionHelper.GetMethodDefinition<Int32>(x => x.Equals((Int32)0)),
				ReflectionHelper.GetMethodDefinition<Int64>(x => x.Equals((Int64)0)),
				ReflectionHelper.GetMethodDefinition<UInt16>(x => x.Equals((UInt16)0)),
				ReflectionHelper.GetMethodDefinition<UInt32>(x => x.Equals((UInt32)0)),
				ReflectionHelper.GetMethodDefinition<UInt64>(x => x.Equals((UInt64)0)),
				ReflectionHelper.GetMethodDefinition<Single>(x => x.Equals((Single)0)),
				ReflectionHelper.GetMethodDefinition<Double>(x => x.Equals((Double)0)),
				ReflectionHelper.GetMethodDefinition<Boolean>(x => x.Equals(true)),
				ReflectionHelper.GetMethodDefinition<Char>(x => x.Equals((Char)0)),
				ReflectionHelper.GetMethodDefinition<Decimal>(x => x.Equals((Decimal)0)),
				ReflectionHelper.GetMethodDefinition<Guid>(x => x.Equals(Guid.Empty)),
				// the parser works better with strongly types instances rather than object
				// for generic objects we have to create a IRuntimeMethodHqlGenerator object
				// ReflectionHelper.GetMethodDefinition<object>(x => x.Equals(null)),
			};
		}

		public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, 
			ReadOnlyCollection<Expression> arguments, 
			HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
		{
			return treeBuilder.Equality(
					visitor.Visit(targetObject).AsExpression(),
					visitor.Visit(arguments[0]).AsExpression());
		}
	}
}
